﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Threading;
using BaseHelper.Net;
using BaseHelper.Encrypt;

namespace DeviceSDK.LED.XianKe.XianKe
{
    public class RXTX_SDK
    {
        private TcpClientHelper _tcp;
        private UdpHelper _udp;
        public SocketMode _socketMode = SocketMode.TCP;
        public int _udpPort = 12004;
        public string _remoteIP;

        private bool _isBusying = false;

        private int _fileBlockSize = 2048;//8100;
        private int _timeout = 3000;
        private byte[] _lastCmdType;
        private byte[] _lastReceiveBuffer;

        private byte[] _waitCmdType;
 
        public bool IsConnected
        {
            get
            {
                if (_socketMode == SocketMode.TCP)
                {
                    if (_tcp!=null &&  _tcp.IsConnected)
                    {
                        int mills = 15000 / 10;     //15s等待时间
                        while (_isBusying && mills-- > 0)
                        {
                            Thread.Sleep(10);
                        }
                        return true;
                    }
                    return false;
                }
                else
                {
                    return false;
                }
            }
        }

        public bool Connect(string IP,int Port=5000)
        {
            _remoteIP = IP;
            if (_socketMode == SocketMode.TCP)
            {
                if (_tcp == null)
                {
                    _tcp = new TcpClientHelper();
                    _tcp.DataArriveEvent += new TcpClientHelper.DataArriveHandler(_socket_DataArreadEvent);
                    _tcp.DisconnectEvent+=new TcpClientHelper.DisconnectHandler(_tcp_DisconnectEvent);
                }
                return _tcp.Connect(IP, Port, 8192);
            }
            else if(_socketMode==SocketMode.UDP)
            {
                if (_udp == null)
                {
                    _udp = new UdpHelper();
                    _udp.BeginReceive(Port);
                }
            }

            return false;
            
        }

        public void Close() 
        {
            if (_socketMode == SocketMode.TCP)
            {
                if (_tcp != null)
                    _tcp.Close();

            }
            else if (_socketMode == SocketMode.UDP)
            {
               
            }
        
        }

        private void _tcp_DisconnectEvent(string remoteIP)
        {
            _tcp = null;
        }

        public bool Reboot()
        {
            SendTcpData(CmdType.Set_Reboot);

            if (WaitData(CmdType.Set_Reboot, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public bool GetCardState()
        {
            SendTcpData(CmdType.Get_NetStatus);
            if (WaitData(CmdType.Get_NetStatus, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public DeviceTotalState GetTotalStatus()
        {
            SendTcpData(CmdType.Get_TotalState);
            if (WaitData(CmdType.Get_TotalState, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    DeviceTotalState d = new DeviceTotalState();
                    d.Net = _lastReceiveBuffer[1] == 1;
                    d.Power = _lastReceiveBuffer[2] == 1;
                    d.Fan = _lastReceiveBuffer[3] == 1;
                    d.Door = _lastReceiveBuffer[4] == 1;
                    d.System = _lastReceiveBuffer[5] == 1;
                    d.Gate = _lastReceiveBuffer[6] == 1;
                    d.Pixel = _lastReceiveBuffer[7] == 1;
                    d.Light = _lastReceiveBuffer[8] == 1;
                    d.Thunder = _lastReceiveBuffer[9] == 1;

                    return d;                
                }
            }

    
            return null;
        }

        public bool SetSystemTime()
        {
            string dt = DateTime.Now.ToString("yyyyMMddHHmmss");
            byte[] data = Encoding.Default.GetBytes(dt);
            SendTcpData(CmdType.Set_SystemTime, data);
            if (WaitData(CmdType.Set_SystemTime, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }

        public string GetSystemTime()
        {
            SendTcpData(CmdType.Get_SystemTime);

            if (WaitData(CmdType.Get_SystemTime, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    string Year = Encoding.Default.GetString(_lastReceiveBuffer,1,4);
                    string Month = Encoding.Default.GetString(_lastReceiveBuffer, 5, 2);
                    string Day = Encoding.Default.GetString(_lastReceiveBuffer, 7, 2);
                    string Hour = Encoding.Default.GetString(_lastReceiveBuffer, 9, 2);
                    string Min = Encoding.Default.GetString(_lastReceiveBuffer, 11, 2);
                    string Sec = Encoding.Default.GetString(_lastReceiveBuffer, 13, 2);
                    return string.Format("{0}-{1}-{2} {3}:{4}:{5}", Year, Month, Day, Hour, Min, Sec);
                }
                else
                    return null;
            }
            else
                return null;

        }

        public bool SetScreenState(bool IsOpen)
        {
            byte[] data=IsOpen?new byte[]{0x30,0x31}:new byte[]{0x30,0x30};
        
            SendTcpData(CmdType.Set_Screen,data);

            if (WaitData(CmdType.Set_Screen, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }

        public bool SetScreenLight(int val)
        {
            val=val/100*35;

            byte[] data = Encoding.Default.GetBytes(val.ToString().PadLeft(2,'0') +"0000");

            SendTcpData(CmdType.Set_Brightness, data);

            if (WaitData(CmdType.Set_Brightness, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public int GetBrightness()
        {
            SendTcpData(CmdType.Get_Brightness);
            if (WaitData(CmdType.Get_Brightness, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    int val = Convert.ToInt32(Encoding.Default.GetString(_lastReceiveBuffer, 2, 2));
                    float value = Convert.ToSingle(val) / 31.0f * 100.0f;
                    return (int)value;
                }
            }

            return -1;
        }

        public int GetTemperature(out int temp, out int humidity)
        {
            SendTcpData(CmdType.Get_Temperature);
            temp = 0;
            humidity = 0;

            if (WaitData(CmdType.Get_Temperature, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    temp = Convert.ToInt32(Encoding.Default.GetString(_lastReceiveBuffer, 1, 4));
                    humidity = Convert.ToInt32(Encoding.Default.GetString(_lastReceiveBuffer, 5, 4));

                    return temp;
                }
            }
  
            return -1;
        }

        public int GetSmoke()
        {
            SendTcpData(CmdType.Get_Smoke);
            if (WaitData(CmdType.Get_Smoke, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    return Convert.ToInt32(Encoding.Default.GetString(_lastReceiveBuffer, 2, 3)); ;
                }
            }

            return -1;
        }

        public string GetPlaybillName()
        {

            SendTcpData(CmdType.Get_PlayList, null);

            if (WaitData(CmdType.Get_PlayList, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    return Encoding.Default.GetString(_lastReceiveBuffer,1,_lastReceiveBuffer.Length-1);
                }
            }
       
            return null;
        }

        public string GetPlaybillContent()
        {
            //00 32 34 30 30 01 00 00 00 20 
            //CE DA BD AD B7 FE CE F1 C7 F8 5C 4E 20 C1 FA C9 BD BC D3 D3 CD D5 BE 5C 4E 20 20 20 20 B7 E2 B1 D5 
            //0D 0A

            SendTcpData(CmdType.Get_PlayContent, null);

            if (WaitData(CmdType.Get_PlayContent, _timeout))
            {
                if (_lastReceiveBuffer[0] == 1)
                {
                    return Encoding.Default.GetString(_lastReceiveBuffer,1,_lastReceiveBuffer.Length-1);
                }
            }
       
            return null;
        }

        public string GetPlaybillContent(int playbillid)
        {
            string fileName = "list\\" + playbillid.ToString().PadLeft(3, '0') + ".xkl";
            byte[] fielBody = Download(fileName);
            if (fielBody == null)
                return "";

            string fileContent = Encoding.Default.GetString(fielBody);
            return fileContent;
        }

        public bool SetPlaybill(int id)
        {
            byte[] fileName = Encoding.Default.GetBytes(id.ToString().PadLeft(3,'0') + ".xkl");
            SendTcpData(CmdType.Set_PlayList, fileName);

            if (WaitData(CmdType.Set_PlayList, _timeout))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;
        }

        public bool SendPlaybill(int id, PlayBill playbill)
        {
            int imgCount = 0;
            for(int i=playbill.Items.Count-1;i>=0;i--)
            {
                if (playbill.Items[i] is ImageItem)
                {
                    ImageItem it = (ImageItem)playbill.Items[i];

                    if (!File.Exists(it.FilePath))
                    {
                        playbill.Items.RemoveAt(i);
                        continue;
                    }

                    it.FileID = (888 - imgCount).ToString().PadLeft(3, '0');
                    imgCount++;

                    string bmpName = "image\\" + it.FileID + ".bmp";
                    byte[] bmpBody = File.ReadAllBytes(it.FilePath);

                    if (UpLoad(bmpName, bmpBody))
                    
                    {
                        playbill.Items[i] = it;
                        //上传成功
                    }
                    else
                    {
                        playbill.Items[i] = it;
                        //2019.12.10 18:03  贵阳高速集团，因为rxtx这个工控机上传的时候，会发生上传文件错误，下次可能会成功。防止节目单直接删除掉这个页面，所以上传失败也会推送上去。
                        //playbill.Items.RemoveAt(i);
                    }
                }
            }

            string fileContent = playbill.Create();

            byte[] fileBody = Encoding.Default.GetBytes(fileContent);
            string fileName = "list\\" + id.ToString().PadLeft(3, '0') + ".xkl";

            if (UpLoad(fileName, fileBody))
            {
                //Console.WriteLine("节目单发送成功！");
                return true;
            }

            return false;

        }

        #region 已经废弃的
        //        /// <summary>
//        /// 发送文件
//        /// </summary>
//        /// <param name="fileName"></param>
//        /// <param name="fileBody"></param>
//        /// <returns></returns>
//        public bool SendFile(byte[] fileName,byte[] fileBody)
//        {
    
//            int SeekIndex = 1;

//            byte[] data=new byte[2+fileName.Length];
//            data[0] = (byte)_fileBlockSize;
//            data[1] = (byte)(_fileBlockSize >> 8);
//            Array.Copy(fileName, 0,data, 2,fileName.Length);


//            SendTcpData(0x11, data);

//            if (WaitData(CmdType.ReplySetFileNameResult, 3000))
//            {
               
               
//                    if (_lastReceiveBuffer[0] == 1)
//                    {
//                        #region 文件发送
//                        int blockCount = fileBody.Length / _fileBlockSize;
//                        int blockLast = fileBody.Length % _fileBlockSize;

//                        do
//                        {


//                            if (SeekIndex <= blockCount)
//                            {
//                                data = new byte[2 + _fileBlockSize];

//                                data[0] = (byte)SeekIndex;
//                                data[1] = (byte)(SeekIndex >> 8);

//                                Array.Copy(fileBody, (SeekIndex-1) * _fileBlockSize, data, 2, _fileBlockSize);
//                                SendTcpData(0x13, data);

//                                if (WaitData(CmdType.ReplySendFileContent,(3000)))
//                                {

//                                    try
//                                    {
//                                        int retBlockCount = (int)_lastReceiveBuffer[0] + (int)(_lastReceiveBuffer[1] << 8);

//                                        if (retBlockCount == SeekIndex)
//                                        {
//                                            if (_lastReceiveBuffer[2] == 0)
//                                            {
//                                                continue;
//                                            }
//                                            else
//                                            {
//                                                SeekIndex++;
//                                                continue;
//                                            }
//                                        }
//                                        else
//                                            continue;
//                                    }
//                                    catch(Exception ex)
//                                    {

//                                        Console.WriteLine("NovaJT100.JT100_SDK.cs", "SendFile()", ex.Message);
                                       
//                                        return false;
//                                    }
                                    

//                                }
//                                else
//                                {
//                                    //Console.WriteLine("bb");
//                                    continue;
//                                }
//                            }


//                            if (blockLast > 0)
//                            {
//                                data = new byte[2 + blockLast];
//                                data[0] = (byte)SeekIndex;
//                                data[1] = (byte)(SeekIndex >> 8);
//                                Array.Copy(fileBody, _fileBlockSize * (SeekIndex - 1), data, 2, blockLast);
//                                SendTcpData(0x13, data);
//                            }

//                            if (WaitData(CmdType.ReplySendFile, 1000))
//                            {
//                                return _lastReceiveBuffer[0] == 1;
//                            }


//                            if (WaitData(CmdType.ReplySendFileContent, (1000)) )
//                            {
//                                if (_lastReceiveBuffer[2] == 0)
//                                    continue;
//                                else if(_lastReceiveBuffer[2] == 1)
//                                {
//                                    SeekIndex++;
//                                    data = new byte[2];
//                                    data[0] = (byte)SeekIndex;
//                                    data[1] = (byte)(SeekIndex >> 8);
//                                    SendTcpData(0x13, data);

//                                }
//                            }

                           
//                        } while (SeekIndex <= (blockCount+1));

//                        #endregion
//                    }
//                    else if (_lastReceiveBuffer[0] == 2)
//                    {
//                        return true;
//                    }
//                    else if (_lastReceiveBuffer[0] == 0)
//                    {
//                        return false;
//                    }
                
//            }

//            return false;
           
//        }

        //#endregion
        #endregion

        public bool UpLoad(string FileName, string FilePath)
        {
            byte[] fileBody = File.ReadAllBytes(FilePath);
            return UpLoad(FileName, fileBody);
        }

        public bool UpLoad(string FileName, byte[] fileBody)
        {
            byte[] fileName = Encoding.Default.GetBytes(FileName);

            int seek = 0;
            int fileBlock= fileBody.Length/_fileBlockSize;
            int fileRemain=fileBody.Length % _fileBlockSize;

            string head;
            byte[] fileInfo;
            byte[] data;

            int error = 4;
            while(seek<fileBlock)
            {
                head = fileName.Length.ToString().PadLeft(3, '0') + FileName + seek.ToString().PadLeft(4, '0');
                fileInfo = Encoding.Default.GetBytes(head);
                data = new byte[2 + fileInfo.Length + _fileBlockSize];


                data[0] = 0x31;
                data[1] = 0x30;

                Buffer.BlockCopy(fileInfo, 0, data, 2, fileInfo.Length);
                Buffer.BlockCopy(fileBody, seek * _fileBlockSize, data,2 + fileInfo.Length, _fileBlockSize);

                SendTcpData(CmdType.Get_Upload, data);

                if (WaitData(CmdType.Get_Upload, 6000))
                {
                    if (_lastReceiveBuffer[0] == 1)
                    {
                        seek++;
                    }
                    else
                        error--;
                }
                else
                    error--;

                if (error <= 0) 
                    return false;

            }
   
            if (fileRemain == 0)
            {
                head = fileName.Length.ToString().PadLeft(3, '0') + FileName + seek.ToString().PadLeft(4, '0');
                fileInfo = Encoding.Default.GetBytes(head);
                data = new byte[2 + fileInfo.Length];

                data[0] = 0x31;
                data[1] = 0x30;

                Buffer.BlockCopy(fileInfo, 0, data, 2, fileInfo.Length);
                SendTcpData(CmdType.Get_Upload, data);

            }
            else
            {
                head = fileName.Length.ToString().PadLeft(3, '0') + FileName + seek.ToString().PadLeft(4, '0');
                fileInfo = Encoding.Default.GetBytes(head);
                data = new byte[2 + fileInfo.Length + fileRemain];

                data[0] = 0x31;
                data[1] = 0x30;

                Buffer.BlockCopy(fileInfo, 0, data, 2, fileInfo.Length);
                Buffer.BlockCopy(fileBody, fileBlock*_fileBlockSize, data, 2 + fileInfo.Length, fileRemain);

                SendTcpData(CmdType.Get_Upload, data);
            }

            if (WaitData(CmdType.Get_Upload, 8000))
                return _lastReceiveBuffer[0] == 1;
            else
                return false;

        }

        public byte[] Download(string FileName)
        {
            int seek = 0;

            string line = FileName.Length.ToString().PadLeft(3, '0') + FileName + seek.ToString().PadLeft(4, '0');
            byte[] data = Encoding.Default.GetBytes(line);
            SendTcpData(CmdType.Get_Download,data);

            if (WaitData(CmdType.Get_Download, 10000))
            {
                if (_lastReceiveBuffer[0] == 1)
                { 
                    string fileName;
                    byte[] fileBody;
                    if (DecodeFile(_lastReceiveBuffer, out fileName, out fileBody))
                        return fileBody;
                }
                
            }
            
            return null;

        }

        private bool WaitData(byte[] CmdType,int mills)
        {
          
            mills /= 10;
            while (!IsEquals( _lastCmdType, CmdType) && mills-- > 0)
            {
                Thread.Sleep(10);
            }
            _isBusying = false;
            if (IsEquals( _lastCmdType, CmdType))
                return true;
            else
                return false;
           
        }
        
        public void SendTcpData(byte[] cmdType, byte[] data=null)
        {
            if (_tcp == null)
                return;

            _isBusying = true;
            _waitCmdType = cmdType;
            _lastCmdType = null;
            _lastReceiveBuffer = new byte[] { };

            byte[] packData = MakePackage(cmdType, data);
            if(_socketMode==SocketMode.TCP)
                _tcp.SendBytes(packData);
            //else if(_socketMode==SocketMode.UDP)
            //    _udp.Send(_remoteIP, _udpPort, packData);


        }

        public byte[] MakePackage(byte[] cmdType, byte[] data=null)
        {
            byte[] dataArea =data==null?new byte[4]: new byte[4 + data.Length];
            for (int i = 0; i < cmdType.Length; i++)
            {
                dataArea[i] = cmdType[i];
            }

            dataArea[2] = 0x30;
            dataArea[3] = 0x30;

            if (data != null)
            {
                Buffer.BlockCopy(data, 0, dataArea, 4, data.Length);
            }

            ushort crc = CRCHelper.CRC16_XMODEM(dataArea, dataArea.Length);

            byte[] buffer = new byte[4 + dataArea.Length];
 
            Buffer.BlockCopy(dataArea, 0, buffer, 1, dataArea.Length);

            //校验
            buffer[buffer.Length - 3] = (byte)(crc>>8);
            buffer[buffer.Length - 2] = (byte)crc;


            if (data != null)
                buffer = EncodeByte(buffer);

            //帧头
            buffer[0]=0x02;

    
            //帧尾
            buffer[buffer.Length-1]=0x03;



            log("send", buffer,buffer.Length);
            return buffer;
        }

        private byte[] EncodeByte(byte[] data)
        {
            if(data==null)
                return null;

        List<byte> lt = new List<byte>();
        foreach (byte b in data)
        {
            if (b == 0x02)
            {
                lt.Add(0x1b);
                lt.Add(0xe7);
            }
            else if (b == 0x03)
            {
                lt.Add(0x1b);
                lt.Add(0xe8);
            }
            else if (b == 0x1b)
            {
                lt.Add(0x1b);
                lt.Add(0x00);
            }
            else
              lt.Add(b);
            }
         return lt.ToArray();
    
          
        }

        private byte[] DecodeByte(byte[] data)
        {
            List<byte> lt = new List<byte>();
            for (int i = 0; i < data.Length-1; i++)
            {
                if (data[i] == 0x1b && data[i + 1] == 0xe7)
                {
                    lt.Add(0x02);
                    i++;

                }
                else if (data[i] == 0x1b && data[i + 1] == 0xe8)
                {
                    lt.Add(0x03); 
                    i++;

                }
                else if (data[i] == 0x1b && data[i + 1] == 0x00)
                {
                    lt.Add(0x1b); 
                    i++;

                }
                else
                    lt.Add(data[i]);

            }

            lt.Add(data[data.Length-1]);
            return lt.ToArray();
        }

        private void _socket_DataArreadEvent(string remoteIp, byte[] buffer, int len)
        {
            if (buffer[0] != 0x02 || buffer[len - 1] != 0x03)
            {
                log("丢弃", buffer, len);
                return;

            }
            buffer[0] = 0;
            buffer[buffer.Length - 1] = 0;

            buffer = DecodeByte(buffer);

            byte[] cmd = new byte[] { buffer[1], buffer[2] };

            //是否是等待的数据包
            if (IsEquals(_waitCmdType, cmd))
            {
                byte[] data = new byte[len - 8];
                Buffer.BlockCopy(buffer, 5, data, 0, data.Length);

                _lastReceiveBuffer = data;
                _lastCmdType = cmd;
            }
            else
            {
                //不是等待的丢弃掉
            }
        }

        private bool IsEquals(byte[] src, byte[] dst)
        {

            if (src==null || dst==null || src.Length != dst.Length)
                return false;

            for (int i = 0; i < src.Length; i++)
            {
                if (src[i] != dst[i])
                    return false;
            }

            return true;
        
        }

        private bool DecodeFile(byte[] data, out string FileName, out byte[] FileBody)
        {
            int fileNameLen = Convert.ToInt32(Encoding.ASCII.GetString(data, 1, 3));
            string fileName = Encoding.Default.GetString(data, 4, fileNameLen);
            int seek = Convert.ToInt32(Encoding.Default.GetString(data, 4 + fileNameLen, 4));
            byte[] fileBody = new byte[data.Length - 8 - fileNameLen];
            Buffer.BlockCopy(data, 8 + fileNameLen, fileBody, 0, fileBody.Length);

            FileName = fileName;
            FileBody = fileBody;

            return true;
        }

        private void log(string tip, byte[] buffer, int len)
        {
            return;
            string line="【" + tip + "】【"+ len +"】" ;


             line += BitConverter.ToString(buffer, 0,len).Replace("-", " ");
       
            
     
            //File.AppendAllText("d:\\tcplog.txt", line + "\r\n");

            if (len > 100)
                line = line.Substring(0, 100);

            Console.WriteLine(line);

        }

    }
}
